package com.write.program.sound;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import java.io.ByteArrayInputStream;

/**
 * Created with IntelliJ IDEA.
 * Description: 按频率播放声音，由Beeper改编而来
 * User: Endstart
 * Date: 2020-05-10
 * Time: 9:13
 */
public class SoundPlayer {
    public static Clip clip = null;
    private static int sampleRate = 40000;

    private float frequency = 0;
    private boolean isPlayer = false;

    static {
        try {
            clip = AudioSystem.getClip();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void play(float frequency) {
        if (this.frequency != frequency || !isPlayer) {
            this.frequency = frequency;
            stop();
            generateSound();
        }

        if (!isPlayer) {
            clip.loop(Clip.LOOP_CONTINUOUSLY);
            isPlayer = true;
        }
    }

    public void stop() {
        clip.stop();
        clip.close();
        isPlayer = false;

    }

    /**
     * Generates PrintLinkList tone, and assigns it to the Clip.
     */
    private void generateSound() {

        float intFPW = getFramesPerWaveLength(frequency, sampleRate);

        // oddly, the sound does not loop well for less than around 5 or so, wavelengths
        int wavelengths = 20;
        int length = (int) (intFPW * wavelengths);
        byte[] buf = new byte[2 * length];
        AudioFormat af = new AudioFormat(
                sampleRate,
                8,  // sample size in bits
                2,  // channels
                true,  // signed
                false  // bigendian
        );

        for (int i = 0; i < length; i++) {
            double angle = ( (i * 2) / intFPW) * (Math.PI);
            buf[i * 2] = getByteValue(angle);
            buf[i * 2 + 1] = buf[i * 2];
        }

        try {
            AudioInputStream ais = new AudioInputStream(new ByteArrayInputStream(buf), af, buf.length / 2);
            clip.open(ais);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static byte getByteValue(double angle) {
        int maxVol = 127;
        return (new Integer((int)Math.round(Math.sin(angle)*maxVol))).byteValue();
    }

    /**
     *
     */
    private static float getFramesPerWaveLength(float frequent, int sampleRate) {
        return sampleRate / frequent;
    }

}